const path = require("path");
const glob = require("glob");
const {statSync, readdirSync} = require("fs");
const {getWildcardDirectories} = require("./getWildcardDirectories");
const defaultRootPath = require("./rootPath");

function isIgnored(filename, ignoreFileRegRex) {
  if (!ignoreFileRegRex)
    return false

  if (path.sep !== '/') {
    filename = filename.split(path.sep).join('/')
  }

  return ignoreFileRegRex.test(filename)
}

// 通配符模式查找文件
function getFilesByGlob(dir, ignoreFileRegRex) {
  let files = glob.sync(dir).filter(file =>  !statSync(path.normalize(file)).isDirectory());

  if (!ignoreFileRegRex) {
    return files.map(path.normalize);
  }

  const result = [];
  files.forEach(file => {
    const normalizeFile = path.normalize(file);

    // 排除 jimu.js 这类带.的文件夹
    if (statSync(normalizeFile).isDirectory()) {
      return;
    }

    if (!isIgnored(normalizeFile, ignoreFileRegRex)) {
      result.push(file);
    }
  })
  return result;
}

// 常规递归查找文件 例：/builder
function getFilesByRecurse(dir, ignoreFileRegRex) {
  const files = [];

  function find(dirPath) {
    if (isIgnored(dirPath, ignoreFileRegRex)) {
      return;
    }

    const stats = statSync(dirPath);

    if (!stats.isDirectory()) {
      files.push(dirPath);
      return;
    }

    // 文件夹如果是
    const tempFiles = readdirSync(dirPath);

    if (!tempFiles.length) return;

    tempFiles.forEach(item => {
      find(path.join(dirPath, '/', item))
    })
  }

  find(dir);

  return files
}

function searchFilesByPath(dir, ignore) {
  return dir.includes('\\**\\') || dir.includes('\\*.') ? getFilesByGlob(...arguments) : getFilesByRecurse(...arguments)
}


let rootPath;

// 解析配置项 查询文件
function searchFiles(options) {
  // 没配置root时，找项目目录的上一级，并将项目目录过滤掉
  if (!options?.root) {
    rootPath = path.join(defaultRootPath, '../');

    if (!options?.ignoreFiles) {
      options.ignoreFiles = [];
    }

    options.ignoreFiles.push(`${path.relative(rootPath, defaultRootPath)}`)
  } else {
    rootPath = options.root
  }

  const ignoreFiles = options?.ignoreFiles?.length ? getWildcardDirectories({validatedExcludeSpecs: options.ignoreFiles,}, rootPath) : undefined;

  const includes = options.includes;
  let searchDirs = Array.isArray(includes) ? includes : typeof includes === 'string' ? [includes] : [];

  return searchDirs.map(dir => searchFilesByPath(path.join(rootPath, '/', dir), ignoreFiles)).flat(1)
}

module.exports = searchFiles;
